/*
*    へ　　　　　  ／|
*    /＼7　　   ∠＿/
*    /　│　　 ／　／               
*    │　Z ＿,＜　／　　 /`ヽ     
*    │　　　　　ヽ　　 /　　〉    
*    Y　　　　　  `  /　　/     
*    ｲ ●　､　●　⊂⊃〈　　/       
*    ()  へ　　　　 |　＼       
*    >ｰ ､_　 ィ　 │ ／／        | @author:smily
*    / へ　　 /　ﾉ＜| ＼＼       | @project:net-hole
*    ヽ_ﾉ　　(_／　 │／／        | @file: NhSocket.cpp
*    7　　　　　　　|／          | @time: 2020/12/30 11:22
*====＞―r￣￣`ｰ―＿===========    
*^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/

#include "../include/NhSocket.h"

bool NhSocket::init_socket() {
    if ((local_fd = socket(AF_INET, SOCK_STREAM, 0)) < -1) {
        snprintf(err_msg, sizeof(err_msg), "create socket error:%s(srrno:%d)\n", strerror(errno), errno);
    }
    return true;
}

bool NhSocket::create_local(unsigned int port) {
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
    local_addr.sin_port = htons(port);
    flags = fcntl(local_fd, F_GETFL, 0);
    fcntl(local_fd, F_SETFL, flags | O_NONBLOCK);//设置为非阻塞
    //设置超时
    struct timeval timeout = {3, 0};//3s
    if (setsockopt(local_fd, SOL_SOCKET, SO_SNDTIMEO, (const char *) &timeout, sizeof(timeout)) != 0) {
        snprintf(err_msg, sizeof(err_msg), "set send timeout failed: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    if (setsockopt(local_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *) &timeout, sizeof(timeout)) != 0) {
        snprintf(err_msg, sizeof(err_msg), "set recv timeout failed: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    //设置重用地址，防止Address already in use
    int on = 1;
    setsockopt(local_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    //将本地地址绑定到所创建的套接字上
    if (bind(local_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == -1) {
        snprintf(err_msg, sizeof(err_msg), "bind socket error: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    //开始监听是否有客户端连接
    if (listen(local_fd, 10) == -1) {
        snprintf(err_msg, sizeof(err_msg), "listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    return true;
}

bool NhSocket::accept_link() {
    socklen_t client_len;
    remote_fd = accept(local_fd, (struct sockaddr *) &remote_addr, &client_len);
    if (remote_fd < 0) {
        snprintf(err_msg, sizeof(err_msg), "accept socket error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    return true;
}

bool NhSocket::connect_remote(sockaddr_in socket_addr, const char *ip, unsigned int port) {
    memset(&socket_addr, 0, sizeof(socket_addr));
    socket_addr.sin_family = AF_INET;
    socket_addr.sin_port = htons(port);
    if (inet_pton(AF_INET, ip, &socket_addr.sin_addr) <= 0) {
        snprintf(err_msg, sizeof(err_msg), "inet_pton error for %s\n", ip);
        return false;
    }

    if (connect(local_fd, (struct sockaddr *) &socket_addr, sizeof(socket_addr)) < 0) {
        snprintf(err_msg, sizeof(err_msg), "connect error: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    return true;
}

bool NhSocket::recv_data(int socket_fd, char *buffer, int buffer_len, int &recv_len) {
    memset(buffer, 0, buffer_len);
    recv_len = recv(socket_fd, buffer, buffer_len, 0);
    if (recv_len <= 0) {
        snprintf(err_msg, sizeof(err_msg), "recv data error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    printf("recv :%s\n", buffer);
    return true;
}

bool NhSocket::send_data(int socket_fd, const char *data, int len) {
    if (send(socket_fd, data, len, 0) == -1) {
        snprintf(err_msg, sizeof(err_msg), "send data error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    return true;
}


